#pragma once

#include "Socket.hpp"
#include "TcpServer.hpp"
#include "Util.hpp"
#include "Log.hpp"
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include <unordered_map>

using namespace SocketModule;
using namespace LogModule;

const std::string gspace = " ";
const std::string glinespace = "\r\n";
const std::string glinesep = ": ";

const std::string webroot = "./wwwroot";
const std::string homepage = "index.html";
const std::string page_404 = "404 Not Found";
class HttpRequest
{
public:
    HttpRequest(){}
    std::string Serialize()
    {
        return std::string();
    }
    void ParseReqLine(std::string &ReqLine)
    {
        //GET /HTTP/1.1
        std::stringstream ss;
        ss >> _method >> _uri >> _version;
    }

    // reqstr是一个完整的http request string
    bool Deserialize(std::string &reqstr)
    {
        //1.提取请求行
        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, glinespace);
        LOG(LogLevel::DEBUG) << reqline;

        //对请求行进行反序列化
        ParseReqLine(reqline);

        if(_uri == "/")
        {
            // ./wwwroot/index.html
            _uri = webroot + _uri + homepage;
        }
        else{
            // ./wwwroot/a/b/c.html
            _uri = webroot + _uri;
        }
        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        LOG(LogLevel::DEBUG) << "_version: " << _version;

        return true;
    }
    std::string Uri(){return _uri;}
    ~HttpRequest() {}
private:
    std::string _method;//请求方法
    std::string _uri;//网址
    std::string _version;//Http版本

    std::unordered_map<std::string, std::string> _headers;//报头
    std::string _blankline;//空行
    std::string _text;//请求正文
};


class HttpResponse
{
public:
    HttpResponse() : _blankline(glinespace), _version("HTTP/1.0")
    {}
    // 实现: 成熟的http，应答做序列化，不要依赖任何第三方库！
    std::string Serialize()
    {
        std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;
        std::string resp_header;
        for(auto &header : _headers)
        {
            std::string line = header.first + glinesep + header.second + glinesep;
            resp_header += line;
        }
        return status_line + resp_header + _blankline + _text;
    }

    void SetTargetFile(const std::string &targetfile)
    {
        _targetfile = targetfile;
    }

    void SetCode(int code)
    {
        _code = code;
        switch(code)
        {
            case 200:
                _desc = "ok";
                break;
            case 404:
                _desc = "Not Found";
                break;
            default:
                break;
        }
    }
    void SetHeader(const std::string &key, const std::string &value)
    {
        auto it = _headers.find(key);
        if(it != _headers.end()) return ;
        _headers.insert(std::make_pair(key, value));
    }

    std::string Uri2Suffix(const std::string &targetfile)
    {
        // ./wwwroot/a/b/c.html
        auto pos = targetfile.rfind(".");
        if(pos == std::string::npos) return "/text/html";

        std::string suffix = targetfile.substr(pos);//behind the "."
        if(suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if(suffix == ".jpg")
            return "image/jpeg";
        else if(suffix == ".png")
            return "image/png";
        else
            return "";
    }

    bool MakeResponse()
    {
        if(_targetfile == "./wwwroot/favicon.ico") 
        {
            LOG(LogLevel::DEBUG) << "user request" << _targetfile << "ignore it";
            return false;
        }

        int filesize = 0;
        //相应端存放的是“服务器对客户端请求的具体回应内容”，是数据传输的核心载体。响应头中的 Content-Type 字段（即 MIME 类型）决定
        bool res = Util::ReadFileContent(_targetfile, &_text);

        if (!res)
        {
            _text = "";
            LOG(LogLevel::WARNING) << "client want get : " << _targetfile << " but not found";
            SetCode(404);
            _targetfile = webroot + page_404;
            filesize = Util::FileSize(_targetfile);
            Util::ReadFileContent(_targetfile, &_text);
            std::string suffix = Uri2Suffix(_targetfile);
            SetHeader("Content-Type", suffix);
            SetHeader("Content-Length", std::to_string(filesize));
        }
        else
        {
            LOG(LogLevel::DEBUG) << "读取文件: " << _targetfile;
            SetCode(200);
            filesize = Util::FileSize(_targetfile);
            std::string suffix = Uri2Suffix(_targetfile);
            SetHeader("Conent-Type", suffix);
            SetHeader("Content-Length", std::to_string(filesize));
        }
        return true;
    }

    bool Deserialize(std::string reqstr)
    {
        return true;

    }

    ~HttpResponse(){}

public:
    std::string _version;
    int _code;
    std::string _desc;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;

    std::string _targetfile;
};

class Http
{
public:
    Http(uint16_t port) : tsvrp(std::make_unique<TcpServer>(port))
    {
    }
    void HandlerHttpRquest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        // 收到请求
        std::string httpreqstr;
        // 假设：概率大，读到了完整的请求
        // bug!
        int n = sock->Recv(&httpreqstr); // 浏览器给我发过来的是一个大的http字符串, 其实我们的recv也是有问题的。tcp是面向字节流的.
        if(n > 0)
        {
            std::cout << "##########################" << std::endl;
            std::cout << httpreqstr;
            std::cout << "##########################" << std::endl;

            // 对报文完整性进行审核 -- 缺
            // 所以，今天，我们就不在担心，用户访问一个服务器上不存在的资源了.
            // 我们更加不担心，给用户返回任何网页资源(html, css, js, 图片，视频)..., 这种资源，静态资源！！

            HttpRequest req;
            req.Deserialize(httpreqstr);
            HttpResponse resp;
            resp.SetTargetFile(req.Uri());
            if (resp.MakeResponse())
            {
                std::string response_str = resp.Serialize();
                sock->Send(response_str);
            }
        }

// #ifndef DEBUG
// #define DEBUG
#ifdef DEBUG
        // 收到请求
        std::string httpreqstr;
        // 假设：概率大，读到了完整的请求
        sock->Recv(&httpreqstr); // 浏览器给我发过来的是一个大的http字符串, 其实我们的recv也是有问题的。tcp是面向字节流的.
        std::cout << httpreqstr;

        // 直接构建http应答. 内存级别+固定
        HttpResponse resp;
        resp._version = "HTTP/1.1";
        resp._code = 200; // success
        resp._desc = "OK";

        std::string filename = webroot + homepage; // "./wwwroot/index.html";
        bool res = Util::ReadFileContent(filename, &(resp._text));
        (void)res;
        std::string response_str = resp.Serialize();
        sock->Send(response_str);
#endif
        // 对请求字符串，进行反序列化
    }
    void Start()
    {
        tsvrp->Start([this](std::shared_ptr<Socket> &sock, InetAddr &client)
                     { this->HandlerHttpRquest(sock, client); });
    }
    ~Http()
    {
    }

private:
    std::unique_ptr<TcpServer> tsvrp;
};